﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using OverStore.Runtime.ObjectRepository.CallbackManager;
using OverStore.Exceptions.Configuration;
using OverStore.Runtime.PersistenceServiceProvider;

namespace OverStore.Configuration.ObjectRepository.CallbackManager
{
    /// <summary>
    /// Configuration for creating instances of <see cref="Aggregate{TInstance, TAggregate}"/>
    /// class configured for saving collection.
    /// </summary>
    /// <typeparam name="TInstance">The type of the instance.</typeparam>
    /// <typeparam name="TAggregate">The type of the aggregate.</typeparam>
    public class CollectionAggregateConfiguration<TInstance, TAggregate> : IComponentConfiguration<ICallbackManager<TInstance>>
        where TInstance : class
        where TAggregate : class
    {
        /// <summary>
        /// Gets or sets the delegate that gets aggregate from the instance.
        /// </summary>
        public Func<TInstance, IEnumerable<TAggregate>> GetCollectionAggregate { get; set; }

        /// <summary>
        /// Gets or sets the optional delegate that applies aggregate to instance.
        /// </summary>
        public Action<TInstance, IEnumerable<TAggregate>> SetCollectionAggregate { get; set; }

        /// <summary>
        /// Gets or sets the delegate that restores reference to parent in aggregate instance.
        /// </summary>
        public Action<TInstance, TAggregate, IPersistenceServiceProvider> RestoreRelation { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether OverStore will use instance as parameter 
        /// due reloading aggregate collection.
        /// </summary>
        public bool UseInstanceAsReloadParameter { get; set; }

        /// <summary>
        /// Creates the new instance of <typeparamref name="TComponent"/> type using set of services provided by <paramref name="context"/> object.
        /// </summary>
        /// <param name="context">The context provides access to services shared between components.</param>
        /// <returns>
        /// The new instance of <typeparamref name="TComponent"/> class.
        /// </returns>
        ICallbackManager<TInstance> IComponentConfiguration<ICallbackManager<TInstance>>.CreateComponent(OverStore.Runtime.OverStoreContext.IOverStoreContext context)
        {
            if (GetCollectionAggregate == null)
                throw this.ConfigurationException("Delegate for get collection aggregate from the instance is missing.");
            if (RestoreRelation == null)
                throw this.ConfigurationException("Restore Relation delegate is missing.");
            return new Aggregate<TInstance, TAggregate>(
                context.PersistenceServiceProvider,
                GetCollectionAggregate,
                SetCollectionAggregate,
                RestoreRelation,
                UseInstanceAsReloadParameter);
        }
    }
}
